#include <jni.h>
#include <stdlib.h>   
#include "model_JtsMesh.h"
#include "jts_curvature.h"
#define RETOUR_VALS 13
#define RETOUR_DEUX 2
#define RETOUR_UN 1

JNIEXPORT jobjectArray JNICALL Java_model_JtsMesh_jts_1reaction(JNIEnv *env, jclass jclassj, jobjectArray vertices, jobjectArray triangles){
	JtsSurface *s;
	JtsCourbure *res;
	JtsVec3f *verticesCC;
	JtsTriangle *trianglesCC;
	int size_triangles, size_vertices, i, j;
	jobjectArray result;
	jdouble tmp[RETOUR_VALS];  /* make sure it is large enough! */
	
	
	/* Transformation des tableaux vertices et triangles en verticesCC et trianglesCC*/
	size_vertices = (*env)->GetArrayLength(env, vertices);
	size_triangles = (*env)->GetArrayLength(env, triangles);
	verticesCC = (JtsVec3f *)malloc(sizeof(JtsVec3f)*size_vertices);
	trianglesCC = (JtsTriangle *)malloc(sizeof(JtsTriangle)*size_triangles);
	if (!verticesCC || !trianglesCC) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	printf("size_vertices : %d \tsize_triangles : %d \n", size_vertices, size_triangles);
	/*TODO essayer jfloat vertex[XXX]; (*env)->getFloatArrayRegion(env, arg, 0, 3, vertex) */	
	for (i = 0; i < size_vertices; i++) {
        jobjectArray arg = (*env)->GetObjectArrayElement(env, vertices, i);
		if (arg != NULL) {
			jfloat *vertex = (*env)->GetFloatArrayElements(env, arg, 0);
			if (vertex != NULL) {
				verticesCC[i][0] = vertex[0];
				verticesCC[i][1] = vertex[1];
				verticesCC[i][2] = vertex[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	/*TODO aussi */
	for(i = 0; i < size_triangles; i++) {
		jobjectArray arg = (*env)->GetObjectArrayElement(env, triangles, i);
		if (arg != NULL) {
			jint *triangle = (*env)->GetIntArrayElements(env, arg, 0);
			if (triangle != NULL) {
				trianglesCC[i][0] = triangle[0];
				trianglesCC[i][1] = triangle[1];
				trianglesCC[i][2] = triangle[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	
	
	/* Construire la surface GTS */
	s = jts_build_surface(verticesCC, size_vertices, trianglesCC, size_triangles);
	verticesCC=NULL;
	trianglesCC=NULL;
	res = (JtsCourbure *)malloc(sizeof(JtsCourbure)*size_vertices);
	if (!res) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	
	
	/* Calculer les courbures gaussiennes, moyennes et principales */
	jts_curvatures(s, res);
	
	
	/* Creer et remplir le tableau des resultats de taille num_vertices*13 */
	jclass doubleArrCls = (*env)->FindClass(env, "[D");
	if (doubleArrCls == NULL) {
		return NULL; /* exception thrown */
	}
	result = (*env)->NewObjectArray(env, size_vertices, doubleArrCls, NULL);
	if (result == NULL) {
		return NULL; /* out of memory error thrown */
	}
	
	for (i = 0; i < size_vertices; i++) {
		jdoubleArray iarr = (*env)->NewDoubleArray(env, RETOUR_VALS);
		if (iarr == NULL) {
			return NULL; /* out of memory error thrown */
		}
		for (j = 0; j < RETOUR_VALS; j++) {
			tmp[j] = res[i][j];
		}
		(*env)->SetDoubleArrayRegion(env, iarr, 0, RETOUR_VALS, tmp);
		(*env)->SetObjectArrayElement(env, result, i, iarr);
		(*env)->DeleteLocalRef(env, iarr);
	}
	
	return result;
}


JNIEXPORT jobjectArray JNICALL Java_model_JtsMesh_jts_1double_1curvatures(JNIEnv *env, jclass jclassj, jobjectArray vertices, jobjectArray triangles){
	JtsSurface *s;
	JtsCourbure2 *res;
	JtsVec3f *verticesCC;
	JtsTriangle *trianglesCC;
	int size_triangles, size_vertices, i;
	jobjectArray result;
	jdouble tmp[RETOUR_DEUX];  /* make sure it is large enough! */
	
	
	/* Transformation des tableaux vertices et triangles en verticesCC et trianglesCC*/
	size_vertices = (*env)->GetArrayLength(env, vertices);
	size_triangles = (*env)->GetArrayLength(env, triangles);
	verticesCC = (JtsVec3f *)malloc(sizeof(JtsVec3f)*size_vertices);
	trianglesCC = (JtsTriangle *)malloc(sizeof(JtsTriangle)*size_triangles);
	if (!verticesCC || !trianglesCC) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	printf("size_vertices : %d \tsize_triangles : %d \n", size_vertices, size_triangles);
	/*TODO essayer jfloat vertex[XXX]; (*env)->getFloatArrayRegion(env, arg, 0, 3, vertex) */	
	for (i = 0; i < size_vertices; i++) {
        jobjectArray arg = (*env)->GetObjectArrayElement(env, vertices, i);
		if (arg != NULL) {
			jfloat *vertex = (*env)->GetFloatArrayElements(env, arg, 0);
			if (vertex != NULL) {
				verticesCC[i][0] = vertex[0];
				verticesCC[i][1] = vertex[1];
				verticesCC[i][2] = vertex[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	/*TODO aussi */
	for(i = 0; i < size_triangles; i++) {
		jobjectArray arg = (*env)->GetObjectArrayElement(env, triangles, i);
		if (arg != NULL) {
			jint *triangle = (*env)->GetIntArrayElements(env, arg, 0);
			if (triangle != NULL) {
				trianglesCC[i][0] = triangle[0];
				trianglesCC[i][1] = triangle[1];
				trianglesCC[i][2] = triangle[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	
	
	/* Construire la surface GTS */
	s = jts_build_surface(verticesCC, size_vertices, trianglesCC, size_triangles);
	verticesCC=NULL;
	trianglesCC=NULL;
	res = (JtsCourbure2 *)malloc(sizeof(JtsCourbure2)*size_vertices);
	if (!res) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	
	/* Calculer les courbures gaussiennes et moyennes */
	jts_double_curvatures(s, res);
	
	
	/* Creer et remplir le tableau des resultats de taille num_vertices*2 */
	jclass doubleArrCls = (*env)->FindClass(env, "[D");
	if (doubleArrCls == NULL) {
		return NULL; /* exception thrown */
	}
	result = (*env)->NewObjectArray(env, size_vertices, doubleArrCls, NULL);
	if (result == NULL) {
		return NULL; /* out of memory error thrown */
	}
	
	for (i = 0; i < size_vertices; i++) {
		jdoubleArray iarr = (*env)->NewDoubleArray(env, RETOUR_DEUX);
		if (iarr == NULL) {
			return NULL; /* out of memory error thrown */
		}
		tmp[0] = res[i][0];
		tmp[1] = res[i][1];
		
		(*env)->SetDoubleArrayRegion(env, iarr, 0, RETOUR_DEUX, tmp);
		(*env)->SetObjectArrayElement(env, result, i, iarr);
		(*env)->DeleteLocalRef(env, iarr);
	}
	
	return result;
}


JNIEXPORT jdoubleArray JNICALL Java_model_JtsMesh_jts_1mean_1curvatures(JNIEnv *env, jclass jclassj, jobjectArray vertices, jobjectArray triangles){
	JtsSurface *s;
	double *res;
	JtsVec3f *verticesCC;
	JtsTriangle *trianglesCC;
	int size_triangles, size_vertices, i;
	jdoubleArray result;
	
	
	/* Transformation des tableaux vertices et triangles en verticesCC et trianglesCC*/
	size_vertices = (*env)->GetArrayLength(env, vertices);
	size_triangles = (*env)->GetArrayLength(env, triangles);
	verticesCC = (JtsVec3f *)malloc(sizeof(JtsVec3f)*size_vertices);
	trianglesCC = (JtsTriangle *)malloc(sizeof(JtsTriangle)*size_triangles);
	if (!verticesCC || !trianglesCC) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	printf("size_vertices : %d \tsize_triangles : %d \n", size_vertices, size_triangles);
	/*TODO essayer jfloat vertex[XXX]; (*env)->getFloatArrayRegion(env, arg, 0, 3, vertex) */	
	for (i = 0; i < size_vertices; i++) {
        jobjectArray arg = (*env)->GetObjectArrayElement(env, vertices, i);
		if (arg != NULL) {
			jfloat *vertex = (*env)->GetFloatArrayElements(env, arg, 0);
			if (vertex != NULL) {
				verticesCC[i][0] = vertex[0];
				verticesCC[i][1] = vertex[1];
				verticesCC[i][2] = vertex[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	/*TODO aussi */
	for(i = 0; i < size_triangles; i++) {
		jobjectArray arg = (*env)->GetObjectArrayElement(env, triangles, i);
		if (arg != NULL) {
			jint *triangle = (*env)->GetIntArrayElements(env, arg, 0);
			if (triangle != NULL) {
				trianglesCC[i][0] = triangle[0];
				trianglesCC[i][1] = triangle[1];
				trianglesCC[i][2] = triangle[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	
	
	/* Construire la surface GTS */
	s = jts_build_surface(verticesCC, size_vertices, trianglesCC, size_triangles);
	verticesCC=NULL;
	trianglesCC=NULL;
	res = (double *)malloc(sizeof(double)*size_vertices);
	if (!res) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	
	
	/* Calculer les courbures moyennes */
	jts_mean_curvatures(s, res);
	
	
	/* Creer et remplir le tableau des resultats de taille num_vertices */
	result = (*env)->NewDoubleArray(env, size_vertices);
	if (result == NULL) {
		return NULL; /* out of memory error thrown */
	}
	
	(*env)->SetDoubleArrayRegion(env, result, 0, size_vertices, res);
	
	return result;
}


JNIEXPORT jdoubleArray JNICALL Java_model_JtsMesh_jts_1gaussian_1curvatures(JNIEnv *env, jclass jclassj, jobjectArray vertices, jobjectArray triangles){
	JtsSurface *s;
	double *res;
	JtsVec3f *verticesCC;
	JtsTriangle *trianglesCC;
	int size_triangles, size_vertices, i;
	jdoubleArray result;
	
	
	/* Transformation des tableaux vertices et triangles en verticesCC et trianglesCC*/
	size_vertices = (*env)->GetArrayLength(env, vertices);
	size_triangles = (*env)->GetArrayLength(env, triangles);
	verticesCC = (JtsVec3f *)malloc(sizeof(JtsVec3f)*size_vertices);
	trianglesCC = (JtsTriangle *)malloc(sizeof(JtsTriangle)*size_triangles);
	if (!verticesCC || !trianglesCC) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	printf("size_vertices : %d \tsize_triangles : %d \n", size_vertices, size_triangles);
	/*TODO essayer jfloat vertex[XXX]; (*env)->getFloatArrayRegion(env, arg, 0, 3, vertex) */	
	for (i = 0; i < size_vertices; i++) {
        jobjectArray arg = (*env)->GetObjectArrayElement(env, vertices, i);
		if (arg != NULL) {
			jfloat *vertex = (*env)->GetFloatArrayElements(env, arg, 0);
			if (vertex != NULL) {
				verticesCC[i][0] = vertex[0];
				verticesCC[i][1] = vertex[1];
				verticesCC[i][2] = vertex[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	/*TODO aussi */
	for(i = 0; i < size_triangles; i++) {
		jobjectArray arg = (*env)->GetObjectArrayElement(env, triangles, i);
		if (arg != NULL) {
			jint *triangle = (*env)->GetIntArrayElements(env, arg, 0);
			if (triangle != NULL) {
				trianglesCC[i][0] = triangle[0];
				trianglesCC[i][1] = triangle[1];
				trianglesCC[i][2] = triangle[2];
			}
		}
		(*env)->DeleteLocalRef(env, arg);
	}
	
	
	/* Construire la surface GTS */
	s = jts_build_surface(verticesCC, size_vertices, trianglesCC, size_triangles);
	verticesCC=NULL;
	trianglesCC=NULL;
	res = (double *)malloc(sizeof(double)*size_vertices);
	if (!res) {
		fprintf(stderr, "malloc impossible");
		exit(-1);
	}
	
	
	/* Calculer les courbures gaussiennes */
	jts_gaussian_curvatures(s, res);
	
	
	/* Creer et remplir le tableau des resultats de taille num_vertices */
	result = (*env)->NewDoubleArray(env, size_vertices);
	if (result == NULL) {
		return NULL; /* out of memory error thrown */
	}
	
	(*env)->SetDoubleArrayRegion(env, result, 0, size_vertices, res);
	
	return result;
}

